﻿using Emgu.CV.Structure;
using Emgu.CV;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvApplication.View.CommonView;
using System.IO;
using System.Diagnostics;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace OpenCvApplication
{
    public partial class FrmImageDenoising : Form
    {
        private readonly FrmMain? _frmMain = null;
        public FrmImageDenoising()
        {
            InitializeComponent();
        }
        public FrmImageDenoising(FrmMain frmMain) : this()
        {
            _frmMain = frmMain;
            _frmMain.Start = Start;
        }
        public void Start()
        {
            if (_isRun)
            {
                MessageBox.Show("正在运行");
                return;
            }
            bool isMultifile = _frmMain.IsMultifile;
            string path = _frmMain.ImagePath;
            string savePath = _frmMain.SavePath;
            if (!isMultifile)
            {
                if (!File.Exists(path))
                {
                    MessageBox.Show("文件不存在");
                    return;
                }
            }
            else
            {
                if (!Path.Exists(path))
                {
                    MessageBox.Show("文件夹不存在");
                    return;
                }
            }
            if (!Path.Exists(savePath))
                Directory.CreateDirectory(savePath);

            if (_selectIndex == -1)
            {
                MessageBox.Show("请选择算法");
                return;
            }
            _isRun = true;
            _isSuspend = false;
            _frmMain.ProgressBarValue = 0;
            Task.Run(() =>
            {
                AlgorithmSelection(isMultifile, path, savePath);
            });
        }
        private void AlgorithmSelection(bool isMultifile, string path, string savePath)
        {
            try
            {
                if (!isMultifile)
                {
                    _frmMain.ProgressBarMaxValue = 1;
                    Stopwatch sw = Stopwatch.StartNew();
                    LoadSrc(path, Path.Combine(savePath, Path.GetFileName(path)));
                    sw.Stop();
                    _frmMain.SetShowTime = sw.ElapsedMilliseconds;
                    _frmMain.ProgressBarValue = 1;
                }
                else
                {
                    var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
                            .Where(file => _frmMain.ImageExtensions.Contains(Path.GetExtension(file).ToLower())).ToArray();

                    _frmMain.ProgressBarMaxValue = files.Length;
                    for (int i = 0; i < files.Length; i++)
                    {
                        if (!_isRun)
                            break;
                        while (_isSuspend)
                        {
                            Thread.Sleep(100);
                        }
                        Stopwatch sw = Stopwatch.StartNew();
                        var file = files[i];

                        LoadSrc(file, Path.Combine(savePath, Path.GetFileName(file)));

                        sw.Stop();
                        _frmMain.SetShowTime = sw.ElapsedMilliseconds;

                        _frmMain.ProgressBarValue = i + 1;
                    }
                }
            }
            catch(Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
            finally
            {
                _isRun = false;
                _isSuspend = true;
            }
        }
        private void SaveImg(string file, Bitmap bitmap)
        {
            if (!_frmMain.IsSave)
                return;

            bitmap.Save(file);
        }
        private Mat srcMat;
        private Mat dstMat;
        private void LoadSrc(string imgPath, string saveImgPath)
        {
            srcMat?.Dispose();
            dstMat?.Dispose();

            srcMat = CvInvoke.Imread(imgPath, Emgu.CV.CvEnum.LoadImageType.Color);
            _frmMain.ShowImageAgo = srcMat.Bitmap;
            dstMat = new Mat();
            switch (_selectIndex)
            {
                case 0:
                    BoxFilter(srcMat, dstMat);
                    break;
                case 1:
                    Blur(srcMat, dstMat);
                    break;
                case 2:
                    GaussianBlur(srcMat, dstMat);
                    break;
                case 3:
                    MedianBlur(srcMat, dstMat);
                    break;
                case 4:
                    BilateralFilter(srcMat, dstMat);
                    break;
            }

            if (dstMat != null)
            {
                _frmMain.ShowImageAfter = dstMat.Bitmap;
                SaveImg(saveImgPath, dstMat.Bitmap);
            }
        }
        private BoxFilterEventArgs _boxFilterEventArgs;
        private void BoxFilter(Mat srcMat, Mat dstMat)
        {
            try
            {
                // 方框滤波
                // 参数3：图像的深度；参数4：内核大小；参数5：描点，(-1,-1)表示在核的中心
                CvInvoke.BoxFilter(srcMat, dstMat, _boxFilterEventArgs.IsUseOriginalDepth ? srcMat.Depth : _boxFilterEventArgs.Depth,
                    new Size(_boxFilterEventArgs.SizeWidth, _boxFilterEventArgs.SizeHeight), new Point(_boxFilterEventArgs.X, _boxFilterEventArgs.Y));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private BlurFilterEventArgs _blurFilterEventArgs;
        private void Blur(Mat srcMat, Mat dstMat)
        {
            try
            {
                // 均值滤波
                // 参数3：内核大小；参数4：描点，(-1,-1)表示在核的中心
                CvInvoke.Blur(srcMat, dstMat, new Size(_blurFilterEventArgs.SizeWidth, _blurFilterEventArgs.SizeHeight), new Point(_blurFilterEventArgs.X, _blurFilterEventArgs.Y));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private GaussianBlurEventArgs _gaussianBlurEventArgs;
        private void GaussianBlur(Mat srcMat, Mat dstMat)
        {
            try
            {
                // 高斯模糊滤波
                // 参数3：高斯内核大小；参数4：高斯核函数在x方向的标准偏差
                CvInvoke.GaussianBlur(srcMat, dstMat, new Size(_gaussianBlurEventArgs.SizeWidth, _gaussianBlurEventArgs.SizeHeight), _gaussianBlurEventArgs.SigmaX, _gaussianBlurEventArgs.SigmaY, _gaussianBlurEventArgs.BorderTypes);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private MedianBlurEventArgs _medianBlurEventArgs;
        private void MedianBlur(Mat srcMat, Mat dstMat)
        {
            try
            {
                // 均值滤波
                // 参数3：孔径的线性尺寸，必须大于1
                CvInvoke.MedianBlur(srcMat, dstMat, _medianBlurEventArgs.KSize);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private BilateralFilterEventArgs _bilateralFilterEventArgs;
        private void BilateralFilter(Mat srcMat, Mat dstMat)
        {
            try
            {
                // 双边滤波
                // 参数3：过滤过程中每个像素邻域的直径；参数4：颜色空间滤波器，值越大，会产生较大的半相等颜色区域
                // 参数5：坐标空间滤波器，值越大，会使更大的区域足够相似的颜色获取相同的颜色
                CvInvoke.BilateralFilter(srcMat, dstMat, _bilateralFilterEventArgs.NeighborhoodDiameter, _bilateralFilterEventArgs.ColorSpaceFilter, _bilateralFilterEventArgs.CoordinateSpaceFilter);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private short _selectIndex = -1;
        /// <summary>
        /// 算法选中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void radioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (panel5.HasChildren)
                panel5.Controls.Clear();

            RadioButton radio = sender as RadioButton;
            UserControl userControl = null;
            switch (radio.Text)
            {
                case "高斯滤波":
                    var gsb = new GaussianBlurParameterControl(); ;
                    userControl = gsb;
                    _gaussianBlurEventArgs = gsb.Args;
                    gsb.ValueChange = GaussianBlurValueChange;
                    break;
                case "方框滤波":
                    var box = new BoxFilterParameterControl();
                    userControl = box;
                    box.ValueChange = BoxFilterValueChange;
                    break;
                case "均值滤波":
                    var blur = new BlurParameterControl();
                    userControl = blur;
                    blur.ValueChange = BlurFilterValueChange;
                    break;
                case "中值滤波":
                    var med = new MedianBlurParameterControl();
                    userControl = med;
                    med.ValueChange = MedianBlurValueChange;
                    break;
                case "双边滤波":
                    var bf = new BilateralFilterParameterControl();
                    userControl = bf;
                    bf.ValueChange = BilateralValueChange;
                    break;
            }
            _selectIndex = Convert.ToInt16(radio.Tag);
            panel5.Controls.Add(userControl);

            if (!string.IsNullOrWhiteSpace(_frmMain.ImagePath))
                Start();
        }
        private void GaussianBlurValueChange(object sender, GaussianBlurEventArgs args)
        {
            _gaussianBlurEventArgs = args;
        }
        private void BoxFilterValueChange(object sender, BoxFilterEventArgs args)
        {
            _boxFilterEventArgs = args;
        }
        private void BlurFilterValueChange(object sender, BlurFilterEventArgs args)
        {
            _blurFilterEventArgs = args;
        }
        private void MedianBlurValueChange(object sender, MedianBlurEventArgs args)
        {
            _medianBlurEventArgs = args;
        }
        private void BilateralValueChange(object sender, BilateralFilterEventArgs args)
        {
            _bilateralFilterEventArgs = args;
        }
        private void FrmImageDenoising_Load(object sender, EventArgs e)
        {
            foreach (Control item in panel1.Controls)
            {
                if (item is RadioButton rad)
                    rad.Click += radioButton_CheckedChanged;
            }
        }
        private void FrmImageDenoising_FormClosing(object sender, FormClosingEventArgs e)
        {
            dstMat?.Dispose();
            srcMat?.Dispose();
            this.Dispose();
        }
        private volatile bool _isSuspend = true;
        /// <summary>
        /// 暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            _isSuspend = true;
        }

        private volatile bool _isRun = false;
        /// <summary>
        /// 停止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        {
            _isRun = false;
        }
    }
}
